﻿using GanFeng.Forest.WebApi.Configs;
using GanFeng.Forest.WebApi.Exceptions;
using GanFeng.Forest.WebApi.Objects;
using hyjx.comm;
using hyjx.comm.Exceptions;
using hyjx.comm.Interfaces;
using hyjx.comm.Types;
using Hyjx.GanFengLogger;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using S7.Net;

namespace GanFeng.Forest.WebApi.Controllers
{
    /// <summary>
    /// 上料系统控制器
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class StorageJarController : ApiControllerBase<StorageJarController>
    {
        IS7Protocol? _plc;

        /// <summary>
        /// 创建一个新的存储罐控制器
        /// </summary>
        /// <param name="logger">日志</param>
        /// <param name="config">配置</param>
        public StorageJarController(ILogger<StorageJarController> logger, IConfiguration config) : base(logger, config)
        {
        }

        /// <summary>
        /// 投料，接口 Id: 210
        /// </summary>
        /// <param name="args">参数</param>
        /// <response code="200">执行完毕</response>
        [HttpPost(nameof(Feeding))]
        [ProducesResponseType(StatusCodes.Status200OK)]
        public async Task<ActionResult> Feeding(FeedingArgs args)
        {
            LogObject log = InitializeLog(args.DeviceCode, 210, args);

            try
            {
                PlcConfig device = GetDevicePlc(args.DeviceCode); // 拿到设备所属 PLC
                //if (device.FeatureType == PlcFeatureTypes.Mix || device.FeatureType == PlcFeatureTypes.Frl)
                //{
                //    EnsureArgsAndCovertMaterialCode(args, device.FeatureType); // 确认参数
                //}

                _plc = new S7Protocol(device.CpuType, device.Ip, device.Rack, device.Slot);
                TankConfig tank = GetFeedingTank(args.DeviceCode);
                var valid = false;
                for (int i = 0; i < 5; i++)
                {
                    _plc.Write(tank.MesValidAddress, true); // 写 Mes 验证结果为 true
                    await Task.Delay(TimeSpan.FromMilliseconds(180));
                    valid = _plc.ReadBool(tank.MesValidAddress);
                    if (valid) break;
                }
                MesVisitSucceed += $"Mes valid addr:{tank.MesValidAddress},Value:{valid}";

                // M2 没有上料系统，M4 上料系统对接宏工，故不走上料系统 MES 处理逻辑
                if (Factory != 2 && Factory != 4)
                {
                    await Task.Run(() =>
                    {
                        // 参数说明：
                        // 参数 1 表示要监控 Mes 校验设置功能
                        // 参数 2 表示 CPU 类型
                        // 参数 3 表示 CPU IP
                        // 参数 4 表示 CPU 机架
                        // 参数 5 表示 CPU 插槽
                        // 参数 6 表示物料 Mes 验证结果地址
                        // 参数 7 表示上料地址
                        // 参数 8 表示上料重量地址
                        // 参数 9 表示 MES 验证通过持续分钟数
                        // 参数 10 表示 WebApi 基本地址
                        // 参数 11 表示设备编码
                        // 参数 12 表示接口 ID
                        // 参数 13 表示物料编码
                        ExecuteFeedingSystemTimedTask($"3,{(int)device.CpuType},{device.Ip},{device.Rack},{device.Slot},{tank.MesValidAddress},{tank.FillingAddress},{tank.WeightAddress},{SystemSetting?.MesValidKeepMinutes},{SystemSetting?.MesApiBaseUrl},{args.DeviceCode},211,{args.MaterialCode}");
                    });
                }
                return OkResult(log);
            }
            catch (EnsureArgsAndCovertMaterialCodeException ex)
            {
                return BadResult(ex.Code, log);
            }
            catch (GetDevicePlcException ex)
            {
                return BadResult(ex.Code, log);
            }
            catch (GetFeedingTankException ex)
            {
                return BadResult(ex.Code, log);
            }
            catch (Exception ex)
            {
                int code = 6;
                switch (ex.Message)
                {
                    case nameof(S7ProtocolReadException):
                    case nameof(S7ProtocolWriteException):
                        code = 11;
                        break;
                    default:
                        break;
                }
                return ExceptionResult(code, ex, log);
            }
            finally
            {
                _plc?.Dispose();
            }
        }
    }
}
